﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;
using Microsoft.Xna.Framework.Net;
using Microsoft.Xna.Framework.Storage;

namespace Kaleta.Xna.Timing
{
    public enum TimeRepeat
    {
        None = 0,
        Once = 1,
        Twice = 2,
        Forever = -1,
    }

   



    public class Timer
    {
        private static Dictionary<string, TimedObject> functions = new Dictionary<string, TimedObject>();

        /// <summary>
        /// Runs this function acording to specified TimedObject.
        /// </summary>
        /// <param name="functionName">Unique name for this timing within application</param>
        /// <param name="gameTime"></param>
        /// <param name="delay"></param>
        /// <param name="everyMillisecond"></param>
        /// <param name="functionToRun"></param>
        public static void Run(TimedObject timedObject, GameTime gameTime, Action functionToRun)
        {
            if (!functions.ContainsKey(timedObject.Key))
                functions.Add(timedObject.Key, timedObject);
            else
                if (functions[timedObject.Key].CanRun(gameTime, timedObject))
                    functionToRun();
        }

        /// <summary>
        /// Runs this function every specified millisecond.
        /// </summary>
        /// <param name="obj">Associated object for this timing within application</param>
        /// <param name="gameTime"></param>
        /// <param name="everyMillisecond"></param>
        /// <param name="functionToRun"></param>
        public static void Run(object obj, GameTime gameTime, double everyMillisecond, Action functionToRun)
        {
            Run(obj.GetHashCode().ToString(), gameTime, everyMillisecond, 0, 0, TimeRepeat.Forever, functionToRun);
        }
        /// <summary>
        /// Runs this function every specified millisecond with a delay.
        /// </summary>
        /// <param name="obj">Associated object for this timing within application</param>
        /// <param name="gameTime"></param>
        /// <param name="delay"></param>
        /// <param name="everyMillisecond"></param>
        /// <param name="functionToRun"></param>
        public static void Run(object obj, GameTime gameTime, double everyMillisecond, double delay, Action functionToRun)
        {
            Run(obj.GetHashCode().ToString(), gameTime, everyMillisecond, delay, 0, TimeRepeat.Forever, functionToRun);
        }

        /// <summary>
        /// Runs this function every specified millisecond with a delay. Furthermore the function stops running after specified duration. 
        /// After the time of duration, the function can be run again acording to specified TimeRepeat value.
        /// </summary>
        /// <param name="obj">Associated object for this timing within application</param>
        /// <param name="gameTime"></param>
        /// <param name="delay"></param>
        /// <param name="everyMillisecond"></param>
        /// <param name="duration"></param>
        /// <param name="behavior"></param>
        /// <param name="functionToRun"></param>
        public static void Run(object obj, GameTime gameTime, double everyMillisecond, double delay, double duration, TimeRepeat behavior, Action functionToRun)
        {
            string key = obj.GetHashCode().ToString();

            if (!functions.ContainsKey(key))
                functions.Add(key, new TimedObject(key));
            else
                if (functions[key].CanRun(gameTime, everyMillisecond, delay, duration, behavior))
                    functionToRun();

        }

        /// <summary>
        /// Runs this function every specified millisecond.
        /// </summary>
        /// <param name="functionName">Unique name for this timing within application</param>
        /// <param name="gameTime"></param>
        /// <param name="everyMillisecond"></param>
        /// <param name="functionToRun"></param>
        public static void Run(string functionName, GameTime gameTime, double everyMillisecond, Action functionToRun)
        {
            Run(functionName, gameTime, everyMillisecond, 0, 0, TimeRepeat.Forever, functionToRun);
        }

        /// <summary>
        /// Runs this function every specified millisecond with a delay.
        /// </summary>
        /// <param name="functionName">Unique name for this timing within application</param>
        /// <param name="gameTime"></param>
        /// <param name="delay"></param>
        /// <param name="everyMillisecond"></param>
        /// <param name="functionToRun"></param>
        public static void Run(string functionName, GameTime gameTime, double everyMillisecond, double delay, Action functionToRun)
        {
            Run(functionName, gameTime, everyMillisecond, delay, 0, TimeRepeat.Forever, functionToRun);
        }

        /// <summary>
        /// Runs this function every specified millisecond with a delay. Furthermore the function stops running after specified duration. 
        /// After the time of duration, the function can be run again acording to specified TimeRepeat value.
        /// </summary>
        /// <param name="functionName">Unique name for this timing within application</param>
        /// <param name="gameTime"></param>
        /// <param name="delay"></param>
        /// <param name="everyMillisecond"></param>
        /// <param name="duration"></param>
        /// <param name="behavior"></param>
        /// <param name="functionToRun"></param>
        public static void Run(string functionName, GameTime gameTime, double everyMillisecond, double delay, double duration, TimeRepeat behavior, Action functionToRun)
        {
            if (!functions.ContainsKey(functionName))
                functions.Add(functionName, new TimedObject(functionName));
            else
                if (functions[functionName].CanRun(gameTime, everyMillisecond, delay, duration, behavior))
                    functionToRun();

        }


        

        

        public static void Reset(string functionName)
        {
            if (!functions.ContainsKey(functionName))
                throw new InvalidOperationException("No '"+ functionName + "' registred");

            functions[functionName] = new TimedObject(functionName);
        }

        public static void Reset(TimedObject obj)
        {
            if (!functions.ContainsKey(obj.Key))
                throw new InvalidOperationException("No '" + obj.Key + "' registred");
            
            TimedObject newObj = new TimedObject(obj.Key) { Behavior = obj.Behavior, Delay = obj.Delay, Duration = obj.Duration, EveryMillisecond = obj.EveryMillisecond };

            functions[obj.Key] = newObj;
            

        }
    }
}
